#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h" 
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "protocol_examples_common.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "m_ble.h"
#include "m_nvs.h"

#include <time.h>
#include "driver/uart.h"
#include "driver/gpio.h"

#include "esp_tls.h"

#include "esp_http_client.h"

#include "m_led.h"
#include "m_uart.h"
#include "m_config.h"
#include "m_http_client.h"


#ifdef usr_use_position_or_heartbreath
#define TimeRTC         1*1000*1000
#define TimePeriod      10*1000*1000
#define TimeTimeout     20*1000*1000
#else
#define TimeRTC         500*1000
#define TimePeriod      3000*1000
#define TimeTimeout     20*1000*1000
#endif

static const char *TAG = "M_HTTP_CLIENT";

extern ble_esp32_param_t m_ble_esp32_param;

extern uint8_t isWifiConnectOk;
uint8_t isnowAudioPost = 0;

extern xQueueHandle led_evt_queue;
extern led_status_e led_status;
xQueueHandle app_data_queue = NULL; //app 数据队列

position_config_t position;
position_config_t position_Old;
static uint8_t isOnePackage = 0;
static uint8_t devbuf[2048];
static uint16_t devbufLen = 0;
static uint8_t devmac[6] = {0};
static char devmacBuf[12+1] = {0};
static char devstr[2048];
static uint16_t devstrLen = 0;
static char devpoststr[2048];
static uint16_t devpoststrLen = 0;

static uint8_t isPositionRP = 1;
static uint8_t isPositionHeart = 0;
esp_timer_handle_t Positioning_timer_handle = 0;
void app_Positioning_time_timer_cb(void)
{
    isPositionHeart = 1;
}

esp_timer_handle_t Timeout_timer_handle = 0;
void app_Timeout_time_timer_cb(void)
{
    esp_timer_stop(Positioning_timer_handle);
    esp_timer_start_periodic(Positioning_timer_handle, TimePeriod); 
    isPositionRP = 1;
}


esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            if (!esp_http_client_is_chunked_response(evt->client)) {
                // Write out data
                // printf("%.*s", evt->data_len, (char*)evt->data);
            }

            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
            int mbedtls_err = 0;
            esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
            if (err != 0) {
                ESP_LOGD(TAG, "Last esp error code: 0x%x", err);
                ESP_LOGD(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
            }
            break;
    }
    return ESP_OK;
}

// const char *post_data = "------qwer1234\r\n"
//                         "Content-Disposition: form-data; name=\"fileSource\"; filename=\"123.txt\"\r\n"
//                         "Content-Type: text/plain\r\n\r\n"
//                         "0123456789\r\n"
//                         "------qwer1234--\r\n";

void m_http_post(uint8_t *devdata, uint8_t *data, uint16_t len)
{
    if(isWifiConnectOk)
    {
        ESP_LOGW(TAG, "m_http_post");
        char *poststr = (char*)heap_caps_malloc(0xA000+1024, MALLOC_CAP_SPIRAM);
        uint16_t poststrLen = 0;

        poststrLen += sprintf(poststr,"------qwer1234\r\nContent-Disposition: form-data; name=\"fileSource\"; filename=\"123.txt\"\r\nContent-Type: text/plain\r\n\r\n");
        for(int i=0;i<len;i++)
        {
            poststrLen += sprintf(poststr+poststrLen,"%c",data[i]);
            //printf("%c",data[i]);
        }
        poststrLen += sprintf(poststr+poststrLen,"\r\n------qwer1234--\r\n");

        printf("AudioPacketLen:%d\r\n",poststrLen);

        devpoststrLen += sprintf(devpoststr,"http://");
        for(int i=0;i<m_ble_esp32_param.ble_char3_IP_len;i++)
        {
            devpoststrLen += sprintf(devpoststr+devpoststrLen,"%1c",m_ble_esp32_param.ble_char3_IP[i]);
        }
        devpoststrLen += sprintf(devpoststr+devpoststrLen,":");
        for(int i=0;i<m_ble_esp32_param.ble_char4_Port_len;i++)
        {
            devpoststrLen += sprintf(devpoststr+devpoststrLen,"%1c",m_ble_esp32_param.ble_char4_Port[i]);
        }
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"/rpt/dc/upload?rpt=");
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"AD@A3A3");
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"%02X",devdata[0]);
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"00");
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"%02X",devdata[1]);
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"00B3B3@");
        for(int k=0;k<6;k++)
        {
            sprintf(devpoststr+devpoststrLen,"%02X",devdata[k+2]);
            devpoststrLen += 2;
        }
        devpoststrLen += sprintf(devpoststr+devpoststrLen,"*Report-%s$",devmacBuf);

        printf("%s\r\n",devpoststr);

        esp_http_client_config_t config = {
            .url = devpoststr,
            .event_handler = _http_event_handler,
            .buffer_size_tx = 50000,
        };
        esp_http_client_handle_t client = esp_http_client_init(&config);
        // POST
        esp_http_client_set_url(client, devpoststr);
        esp_http_client_set_method(client, HTTP_METHOD_POST);
        esp_http_client_set_header(client, "Content-Type", "multipart/form-data;boundary=----qwer1234");

        esp_http_client_set_post_field(client, poststr, poststrLen);
        esp_err_t err = esp_http_client_perform(client);
        if (err == ESP_OK) 
        {
            char mbuf[50];
            uint8_t mlen=0;
            mlen = esp_http_client_get_content_length(client);
            esp_http_client_read(client,mbuf,mlen);

            ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d,%s",
                    esp_http_client_get_status_code(client),
                    mlen, mbuf);

            if(mbuf[20] == '1')
            {
                // ESP_LOGW(TAG, "request ok 1");
            }
            else
            {
                ESP_LOGW(TAG, "request err 0");
            }
        } 
        else 
        {
            ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
        }
        esp_http_client_cleanup(client);

        memset(devpoststr,0,2048);
        devpoststrLen = 0;

        heap_caps_free(poststr);
        poststrLen = 0;
    }

    isnowAudioPost = 0;
}

static void http_client_task(void *pvParameters)
{
    // 队列
    uint8_t buf[256];
    app_data_queue = xQueueCreate(20, 256);

    while (1) {
        if (xQueueReceive(app_data_queue, buf, portMAX_DELAY))
        {
            if(isWifiConnectOk && !isnowAudioPost)
            {
                //手柄报警/取消
                if ((buf[1] == 0xCC) && (buf[2] == 0xCC) && ((buf[3] == 0x01) || (buf[3] == 0x02)) && (buf[buf[0]] == 0xDD) && (buf[buf[0]-1] == 0xDD))
                {
                    devstrLen += sprintf(devstr,"http://");
                    for(int i=0;i<m_ble_esp32_param.ble_char3_IP_len;i++)
                    {
                        devstrLen += sprintf(devstr+devstrLen,"%1c",m_ble_esp32_param.ble_char3_IP[i]);
                    }
                    devstrLen += sprintf(devstr+devstrLen,":");
                    for(int i=0;i<m_ble_esp32_param.ble_char4_Port_len;i++)
                    {
                        devstrLen += sprintf(devstr+devstrLen,"%1c",m_ble_esp32_param.ble_char4_Port[i]);
                    }
                    devstrLen += sprintf(devstr+devstrLen,"/rpt/dc/data?rpt=");
                    //devstrLen += sprintf(devstr+devstrLen,"ST@A3A3");
                    if(buf[5] == 'H')
                    {
                        devstrLen += sprintf(devstr+devstrLen,"ST@A3A3");
                    }
                    else if(buf[5] == 'B')
                    {
                        devstrLen += sprintf(devstr+devstrLen,"AT@A3A3");
                    }
                    devstrLen += sprintf(devstr+devstrLen,"%02X",buf[4]);   // m_batt
                    devstrLen += sprintf(devstr+devstrLen,"00");            
                    devstrLen += sprintf(devstr+devstrLen,"0100");
                    if(buf[3] == 0x02) buf[3] = 0x00;
                    devstrLen += sprintf(devstr+devstrLen,"%02X",buf[3]);   // m_flag
                    devstrLen += sprintf(devstr+devstrLen,"00");            
                    devstrLen += sprintf(devstr+devstrLen,"%02X",buf[6]);   // m_sn
                    devstrLen += sprintf(devstr+devstrLen,"00");
                    devstrLen += sprintf(devstr+devstrLen,"B3B3@");
                    for(int k=0;k<6;k++)
                    {
                        sprintf(devstr+devstrLen,"%02X",buf[k+7]);
                        devstrLen += 2;
                    }
                    devstrLen += sprintf(devstr+devstrLen,"*Report-%s$",devmacBuf);

                    printf("%s\r\n",devstr);
                    
                    esp_http_client_config_t config = {
                        .url = devstr,
                        .event_handler = _http_event_handler,
                    };
                    esp_http_client_handle_t client = esp_http_client_init(&config);
                    // GET
                    esp_http_client_set_url(client, devstr);
                    esp_http_client_set_method(client, HTTP_METHOD_GET);
                    esp_err_t err = esp_http_client_perform(client);
                    if (err == ESP_OK) 
                    {
                        char mbuf[50];
                        uint8_t mlen=0;
                        mlen = esp_http_client_get_content_length(client);
                        esp_http_client_read(client,mbuf,mlen);

                        ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d,%s",
                                esp_http_client_get_status_code(client),
                                mlen, mbuf);

                        if(mbuf[20] == '1')
                        {
                            // ESP_LOGW(TAG, "request ok 1");
                        }
                        else
                        {
                            ESP_LOGW(TAG, "request err 0");
                        }
                    } 
                    else
                    {
                        ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
                    }
                    esp_http_client_cleanup(client);
                }


                #ifdef usr_use_position_or_heartbreath
                {
                    // 定位跌倒
                    if ((buf[1] == 0xA3) && (buf[2] == 0xA3) && (buf[buf[0]] == 0xB3) && (buf[buf[0]-1] == 0xB3))
                    {
                        esp_err_t err;
                        err = esp_timer_start_periodic(Positioning_timer_handle, TimePeriod); 
                        if(err == ESP_OK)
                        {
                            printf("Positioning time timer  start ok!\r\n");
                        }	

                        memcpy(devbuf,buf+1,buf[0]);
                        devbufLen = buf[0];

                        isOnePackage = 2;
                        //ESP_LOGE("","A3B3\r\n");
                    }


                    if ((buf[1] == 0xA3) && (buf[2] == 0xA3) && (buf[buf[0]] != 0xB3) && (buf[buf[0]-1] != 0xB3))
                    {
                        memcpy(devbuf,buf+1,buf[0]);
                        devbufLen = buf[0];

                        isOnePackage = 1;
                        //ESP_LOGE("","A3\r\n");
                    }

                    if((buf[1] != 0xA3) && (buf[2] != 0xA3) && (buf[buf[0]] == 0xB3) && (buf[buf[0]-1] == 0xB3))
                    {
                        memcpy(devbuf+devbufLen,buf+1,buf[0]);
                        devbufLen += buf[0];

                        isOnePackage = 2;
                        //ESP_LOGE("","B3\r\n");
                    }

                    memset(buf,0,256);

                    if(isOnePackage == 2)
                    {
                        uint8_t isNeedTrans = 0;
                        //isPositionHeart = 1;  // 测试实时数据
                        if(!isPositionHeart)
                        {
                            // 轨迹数uint16 由于最多16 所以只取低8位即可
                            position.cnt = devbuf[4];
                            //printf("posture.cnt: %d\r\n",position.cnt);
                            for(int i=0;i<position.cnt;i++)
                            {
                                uint16_t id =  devbuf[6+i*12] + (devbuf[6+i*12]<<8);
                                position.param[i].channel = id & 0x000F; 
                                position.param[i].posture = (id>>4) & 0x0003; 
                                //printf("i: %d,channel: %d,posture: %d\r\n",i,position.param[i].channel,position.param[i].posture);
                            }

                            // 首先判断检测的cnt
                            if(position_Old.cnt != position.cnt)
                            {
                                isNeedTrans = 1;
                                ESP_LOGE("","position.cnt Change");
                            }
                            else
                            {
                                for(int j=0;j<position.cnt;j++)
                                {
                                    if((position_Old.param[j].channel != position.param[j].channel) || (position_Old.param[j].posture != position.param[j].posture))
                                    {
                                        isNeedTrans = 1;
                                        ESP_LOGE("","position.param Change");
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            isPositionHeart = 0;
                            isNeedTrans = 1;
                            ESP_LOGE("","position Heart");
                        }

                        if(isNeedTrans)
                        {
                            devstrLen += sprintf(devstr,"http://");
                            for(int i=0;i<m_ble_esp32_param.ble_char3_IP_len;i++)
                            {
                                devstrLen += sprintf(devstr+devstrLen,"%1c",m_ble_esp32_param.ble_char3_IP[i]);
                            }
                            devstrLen += sprintf(devstr+devstrLen,":");
                            for(int i=0;i<m_ble_esp32_param.ble_char4_Port_len;i++)
                            {
                                devstrLen += sprintf(devstr+devstrLen,"%1c",m_ble_esp32_param.ble_char4_Port[i]);
                            }
                            devstrLen += sprintf(devstr+devstrLen,"/rpt/dc/data?rpt=");
                            devstrLen += sprintf(devstr+devstrLen,"FT@");
                            for(int k=0;k<devbufLen;k++)
                            {
                                sprintf(devstr+devstrLen+k*2,"%02X",devbuf[k]);
                            }
                            devstrLen += devbufLen*2;
                            if(isPositionRP)
                            {
                                devstrLen += sprintf(devstr+devstrLen,"@%s*Report-P$",devmacBuf);
                            }
                            else
                            {
                                devstrLen += sprintf(devstr+devstrLen,"@%s*Report-R$",devmacBuf);
                            }

                            printf("%s\r\n",devstr);

                            esp_http_client_config_t config = {
                                .url = devstr,
                                .event_handler = _http_event_handler,
                            };
                            esp_http_client_handle_t client = esp_http_client_init(&config);
                            // GET
                            esp_http_client_set_url(client, devstr);
                            esp_http_client_set_method(client, HTTP_METHOD_GET);
                            esp_err_t err = esp_http_client_perform(client);
                            if (err == ESP_OK) 
                            {
                                char mbuf[50];
                                uint8_t mlen=0;
                                mlen = esp_http_client_get_content_length(client);
                                esp_http_client_read(client,mbuf,mlen);

                                ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d,%s",
                                        esp_http_client_get_status_code(client),
                                        mlen, mbuf);

                                if(mbuf[20] == '1')
                                {
                                    // ESP_LOGW(TAG, "request ok 1");
                                }
                                else
                                {
                                    ESP_LOGW(TAG, "request err 0");
                                }
                            }
                            else
                            {
                                ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
                            }
                            esp_http_client_cleanup(client);
                        }

                        // 将当前数据赋给old数据
                        position_Old = position;

                        isOnePackage = 0;
                    }
                }
                #else
                {
                    //心率呼吸
                    if ((buf[1] == 0xA4) && (buf[2] == 0xA4) && (buf[buf[0]] == 0xB4) && (buf[buf[0]-1] == 0xB4))
                    {
                        esp_err_t err;
                        err = esp_timer_start_periodic(Positioning_timer_handle, TimePeriod); 
                        if(err == ESP_OK)
                        {
                            printf("Positioning time timer  start ok!\r\n");
                        }

                        if(isPositionHeart)
                        {
                            isPositionHeart = 0;

                            devstrLen += sprintf(devstr,"http://");
                            for(int i=0;i<m_ble_esp32_param.ble_char3_IP_len;i++)
                            {
                                devstrLen += sprintf(devstr+devstrLen,"%1c",m_ble_esp32_param.ble_char3_IP[i]);
                            }
                            devstrLen += sprintf(devstr+devstrLen,":");
                            for(int i=0;i<m_ble_esp32_param.ble_char4_Port_len;i++)
                            {
                                devstrLen += sprintf(devstr+devstrLen,"%1c",m_ble_esp32_param.ble_char4_Port[i]);
                            }
                            devstrLen += sprintf(devstr+devstrLen,"/rpt/dc/data?rpt=");
                            devstrLen += sprintf(devstr+devstrLen,"FT@");
                            for(int k=0;k<buf[0];k++)
                            {
                                sprintf(devstr+devstrLen+k*2,"%02X",buf[k+1]);
                            }
                            devstrLen += buf[0]*2;
                            devstrLen += sprintf(devstr+devstrLen,"@%s*Report-P$",devmacBuf);

                            printf("%s\r\n",devstr);

                            esp_http_client_config_t config = {
                                .url = devstr,
                                .event_handler = _http_event_handler,
                            };
                            esp_http_client_handle_t client = esp_http_client_init(&config);
                            // GET
                            esp_http_client_set_url(client, devstr);
                            esp_http_client_set_method(client, HTTP_METHOD_GET);
                            esp_err_t err = esp_http_client_perform(client);
                            if (err == ESP_OK) 
                            {
                                char mbuf[50];
                                uint8_t mlen=0;
                                mlen = esp_http_client_get_content_length(client);
                                esp_http_client_read(client,mbuf,mlen);

                                ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d,%s",
                                        esp_http_client_get_status_code(client),
                                        mlen, mbuf);

                                if(mbuf[20] == '1')
                                {
                                    // ESP_LOGW(TAG, "request ok 1");
                                }
                                else
                                {
                                    ESP_LOGW(TAG, "request err 0");
                                }
                            } 
                            else
                            {
                                ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
                            }
                            esp_http_client_cleanup(client);
                        }
                    }
                }
                #endif

                memset(devbuf,0,2048);
                devbufLen = 0; 
                memset(devstr,0,2048);
                devstrLen = 0;
            }
        }
    }
}

// void http_connect_process(void)
// {
//     // 等待200ms，刷新一下led闪烁延时while流程
//     vTaskDelay(200 / portTICK_RATE_MS);
//     led_status = led_status_socket_conneting;
//     xQueueSend(led_evt_queue, &led_status, NULL);

//     //延时3S准备建立client，也起到让LED跑一会的作用
//     vTaskDelay(4000 / portTICK_RATE_MS);

//     // esp_http_client_config_t config = {
//     //     .url = "http://192.168.31.77:8043/rpt/dc/data?rpt=",
//     //     .event_handler = _http_event_handler,
//     // };
//     // esp_http_client_handle_t client = esp_http_client_init(&config);
//     // esp_http_client_perform(client);
//     // esp_http_client_cleanup(client);
// }

void http_init(void)
{
    esp_read_mac(devmac, ESP_MAC_BT);//读取BT MAC地址
#ifdef usr_use_wifi_or_eth
    //esp_read_mac(devmac, ESP_MAC_WIFI_STA);//读取WIFI MAC地址
#else
    //esp_read_mac(devmac, ESP_MAC_ETH);//读取ETH MAC地址
#endif
    sprintf((char*)devmacBuf,"%02X%02X%02X%02X%02X%02X",devmac[0],devmac[1],devmac[2],devmac[3],devmac[4],devmac[5]);
    printf("MAC:%s",devmacBuf);

    // 定时器
    esp_err_t err;
	esp_timer_create_args_t app_Positioning_time_timer = 
	{ 
		.callback = &app_Positioning_time_timer_cb, 							//回调函数
		.arg = NULL, 													        //参数
		.name = "Positioning time timer" 										//定时器名称
	};

    // 创建定时器时
	err = esp_timer_create(&app_Positioning_time_timer, &Positioning_timer_handle);
    if(err == ESP_OK)
    {
        printf("Positioning time timer cteate ok!\r\n");
    }

    // 创建一个超时定时器，防止下发周期P的指令没有收到，强制复位为周期Report=P
	esp_timer_create_args_t app_Timeout_time_timer = 
	{ 
		.callback = &app_Timeout_time_timer_cb, 							//回调函数
		.arg = NULL, 													    //参数
		.name = "Timeout time timer" 										//定时器名称
	};	
    esp_timer_create(&app_Timeout_time_timer, &Timeout_timer_handle);

    xTaskCreate(&http_client_task, "http_client_task", 8192, NULL, 8, NULL);
}


